{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "91c6a7ef",
   "metadata": {},
   "source": [
    "# Streamlit\n",
    "\n",
    ">[Streamlit](https://docs.streamlit.io/) is an open-source Python library that makes it easy to create and share beautiful, \n",
    "custom web apps for machine learning and data science.\n",
    "\n",
    "\n",
    "This notebook goes over how to store and use chat message history in a `Streamlit` app. `StreamlitChatMessageHistory` will store messages in\n",
    "[Streamlit session state](https://docs.streamlit.io/library/api-reference/session-state)\n",
    "at the specified `key=`. The default key is `\"langchain_messages\"`.\n",
    "\n",
    "- Note, `StreamlitChatMessageHistory` only works when run in a Streamlit app.\n",
    "- You may also be interested in [StreamlitCallbackHandler](/docs/integrations/callbacks/streamlit) for LangChain.\n",
    "- For more on Streamlit check out their\n",
    "[getting started documentation](https://docs.streamlit.io/library/get-started).\n",
    "\n",
    "You can see the [full app example running here](https://langchain-st-memory.streamlit.app/), and more examples in\n",
    "[github.com/langchain-ai/streamlit-agent](https://github.com/langchain-ai/streamlit-agent)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "d15e3302",
   "metadata": {},
   "outputs": [],
   "source": [
    "from langchain.memory import StreamlitChatMessageHistory\n",
    "\n",
    "history = StreamlitChatMessageHistory(key=\"chat_messages\")\n",
    "\n",
    "history.add_user_message(\"hi!\")\n",
    "history.add_ai_message(\"whats up?\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "64fc465e",
   "metadata": {},
   "outputs": [],
   "source": [
    "history.messages"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b60dc735",
   "metadata": {},
   "source": [
    "You can integrate `StreamlitChatMessageHistory` into `ConversationBufferMemory` and chains or agents as usual. The history will be persisted across re-runs of the Streamlit app within a given user session. A given `StreamlitChatMessageHistory` will NOT be persisted or shared across user sessions."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "42ab5bf3",
   "metadata": {},
   "outputs": [],
   "source": [
    "from langchain.memory import ConversationBufferMemory\n",
    "from langchain.memory.chat_message_histories import StreamlitChatMessageHistory\n",
    "\n",
    "# Optionally, specify your own session_state key for storing messages\n",
    "msgs = StreamlitChatMessageHistory(key=\"special_app_key\")\n",
    "\n",
    "memory = ConversationBufferMemory(memory_key=\"history\", chat_memory=msgs)\n",
    "if len(msgs.messages) == 0:\n",
    "    msgs.add_ai_message(\"How can I help you?\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "a29252de",
   "metadata": {},
   "outputs": [],
   "source": [
    "from langchain.chains import LLMChain\n",
    "from langchain.llms import OpenAI\n",
    "from langchain.prompts import PromptTemplate\n",
    "\n",
    "template = \"\"\"You are an AI chatbot having a conversation with a human.\n",
    "\n",
    "{history}\n",
    "Human: {human_input}\n",
    "AI: \"\"\"\n",
    "prompt = PromptTemplate(input_variables=[\"history\", \"human_input\"], template=template)\n",
    "\n",
    "# Add the memory to an LLMChain as usual\n",
    "llm_chain = LLMChain(llm=OpenAI(), prompt=prompt, memory=memory)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "7cd99b4b",
   "metadata": {},
   "source": [
    "Conversational Streamlit apps will often re-draw each previous chat message on every re-run. This is easy to do by iterating through `StreamlitChatMessageHistory.messages`:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "3bdb637b",
   "metadata": {},
   "outputs": [],
   "source": [
    "import streamlit as st\n",
    "\n",
    "for msg in msgs.messages:\n",
    "    st.chat_message(msg.type).write(msg.content)\n",
    "\n",
    "if prompt := st.chat_input():\n",
    "    st.chat_message(\"human\").write(prompt)\n",
    "\n",
    "    # As usual, new messages are added to StreamlitChatMessageHistory when the Chain is called.\n",
    "    response = llm_chain.run(prompt)\n",
    "    st.chat_message(\"ai\").write(response)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "7adaf3d6",
   "metadata": {},
   "source": [
    "**[View the final app](https://langchain-st-memory.streamlit.app/).**"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.10.12"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
